package cn.liumouren.tool.pac;

import cn.liumouren.tool.pac.entity.*;
import cn.liumouren.tool.pac.entity.rely.Page;
import cn.liumouren.tool.pac.util.MapUtil;
import cn.liumouren.tool.pac.util.QueryUtil;
import cn.liumouren.tool.pac.util.UpdateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.beanutils.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

/**
 * @author Daniel Liu
 * @date 2021/3/4 01:17
 */
public class ApiUtil {

    private static <T> QueryWrapper<T> process(Query query) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();

        // 处理 select
        QueryUtil.processSelect(queryWrapper, query);

        // 处理 where
        QueryUtil.processWhere(queryWrapper, query);

        // 处理 order
        QueryUtil.processOrder(queryWrapper, query);

        return queryWrapper;
    }

    private static <T> UpdateWrapper<T> process(Update update) {
        UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();

        // 处理 set
        UpdateUtil.processSet(updateWrapper, update);

        // 处理 where
        UpdateUtil.processWhere(updateWrapper, update);

        return updateWrapper;
    }

    private static <T> QueryWrapper<T> process(Delete delete) {
        Query query = new Query();
        query.setWhere(delete.getWhere());
        return process(query);
    }

    private static <T> boolean update(IService<T> service, Update update) {
        UpdateWrapper<T> updateWrapper = process(update);
        return service.update(updateWrapper);
    }

    private static <T> PageResult query(IService<T> service, Query query) {
        QueryWrapper<T> queryWrapper = process(query);
        Page page = query.getPage();
        if (page.isFindAll()) {
            List<T> list = service.list(queryWrapper);
            return new PageResult(list, list.size(), 0, 0);
        }
        return new PageResult(service.page(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
                page.getCur(),
                page.getSize(),
                page.isSearchCount()
        ), queryWrapper));
    }

    private static <T> boolean delete(IService<T> service, Delete delete) {
        QueryWrapper<T> queryWrapper = process(delete);
        return service.remove(queryWrapper);
    }

    private static <T> boolean insert(IService<T> service, Insert in) {
        if (service instanceof ServiceImpl) {

            // 通过 ServiceImpl 获取 T 的Class对象
            ServiceImpl<BaseMapper<T>, T> serviceImpl = (ServiceImpl<BaseMapper<T>, T>) service;
            Class<T> clazz = serviceImpl.getEntityClass();

            // 将 key 转为驼峰格式
            Map<String, Object> newMap = MapUtil.changeKeyToCase(in.getEntity());

            // map转为bean
            T t = null;
            try {
                t = clazz.newInstance();
                BeanUtils.populate(t, newMap);
            } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
                e.printStackTrace();
            }

            // save操作
            return service.save(t);
        }
        return false;
    }

    public static <T> PageResult execute(IService<T> service, Mode mode) {
        String curMode = mode.getMode();
        if (Mode.QUERY.equals(curMode)) {
            return query(service, (Query) mode);
        }
        if (Mode.UPDATE.equals(curMode)) {
            update(service, (Update) mode);
            return null;
        }
        if (Mode.DELETE.equals(curMode)) {
            delete(service, (Delete) mode);
            return null;
        }
        if (Mode.INSERT.equals(curMode)) {
            insert(service, (Insert) mode);
            return null;
        }
        return null;
    }

    public static <T> PageResult execute(IService<T> service, Execution execution) {
        // 执行顺序为 query, update, delete, insert
        if (execution.getQuery() != null) {
            return execute(service, execution.getQuery());
        }
        if (execution.getUpdate() != null) {
            return execute(service, execution.getUpdate());
        }
        if (execution.getDelete() != null) {
            return execute(service, execution.getDelete());
        }
        if (execution.getInsert() != null) {
            return execute(service, execution.getInsert());
        }
        return null;
    }
}
